// ClientSocket.cpp : implementation file
//

#include "stdafx.h"
#include "commclientlib.h"
#include "ClientSocket.h"
#include "CommWithServer.h"
#include "ClientSocketThread.h"

#include "CommonLib\Packet.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CClientSocket

CClientSocket::CClientSocket():
m_lpbySendBuf(NULL),
m_nSendDataLen(0),
m_nBytesSent(0),
m_lpbyRecvBuf(NULL),
m_nRecvDataLen(sizeof(DWORD)),
m_nBytesRecv(0),
m_nRecvStatus(RecvId)
{
}

CClientSocket::~CClientSocket()
{
  if (m_lpbyRecvBuf) delete m_lpbyRecvBuf;
  if (m_lpbySendBuf) delete m_lpbySendBuf;
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CClientSocket, CAsyncSocket)
	//{{AFX_MSG_MAP(CClientSocket)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif	// 0

/////////////////////////////////////////////////////////////////////////////
// CClientSocket member functions

void CClientSocket::Init()
{
  const int nBufSize = 0x10000;
  SetSockOpt(SO_RCVBUF, &nBufSize, sizeof(int), SOL_SOCKET);
  SetSockOpt(SO_SNDBUF, &nBufSize, sizeof(int), SOL_SOCKET);
}

void CClientSocket::OnConnect(int nErrorCode) 
{
	// TODO: Add your specialized code here and/or call the base class
  bool bConnect = nErrorCode == 0;

  CommWithServer::Instance()->m_bConnected = bConnect;

  if (!bConnect)
  {
    Close();
    PostQuitMessage(0);
  }

	CAsyncSocket::OnConnect(nErrorCode);
}

void CClientSocket::OnClose(int nErrorCode) 
{
	// TODO: Add your specialized code here and/or call the base class
  CommWithServer::Instance()->m_bConnected = false;

  CommWithServer::Instance()->PostNotification(WM_APP_DISCONNECTED);

  ShutDown();
  Close();
  PostQuitMessage(0);
	
	CAsyncSocket::OnClose(nErrorCode);
}

void CClientSocket::OnReceive(int nErrorCode) 
{
	// TODO: Add your specialized code here and/or call the base class
	int nRead = 0;
	
	// data needs to be read (which should be all the time when this is called)
	if (m_nBytesRecv < m_nRecvDataLen) 
	{
		// make sure we're reading 4 bytes for id or data length
		if (m_nRecvStatus == RecvId || m_nRecvStatus == RecvLength)
		{
			ASSERT(m_nRecvDataLen == sizeof(DWORD));
		}
		
		int nNeedRecv = m_nRecvDataLen-m_nBytesRecv;
		if (!m_lpbyRecvBuf) m_lpbyRecvBuf = new BYTE[m_nRecvDataLen];
		
		// read all the data
		nRead = Receive(&m_lpbyRecvBuf[m_nBytesRecv], nNeedRecv);
		
		// if something was read
		if (nRead > 0) 
		{
			m_nBytesRecv += nRead;
			
			// if all the data was read
			if (m_nBytesRecv == m_nRecvDataLen) 
			{
				// extract data length from packet
				switch (m_nRecvStatus) 
				{
				case RecvId:
					m_dwId = *((LPDWORD)m_lpbyRecvBuf);
					delete m_lpbyRecvBuf;
					m_lpbyRecvBuf = NULL;
					m_nRecvDataLen = sizeof(DWORD);
					m_nBytesRecv = 0;
					m_nRecvStatus = RecvLength;
					break;
					
				case RecvLength:
					m_dwDataSize = *((LPDWORD)m_lpbyRecvBuf);
					delete m_lpbyRecvBuf;
					m_lpbyRecvBuf = NULL;
					m_nRecvDataLen = m_dwDataSize;
					m_nBytesRecv = 0;
					m_nRecvStatus = RecvData;
					break;
					
				case RecvData:
					{
						Packet * pPacket = new Packet(m_dwDataSize, m_lpbyRecvBuf);
						pPacket->m_dwId = m_dwId;
						//TRACE0("Receive a packet!\n");
						delete m_lpbyRecvBuf;
						m_lpbyRecvBuf = NULL;
						
							CClientSocketThread * pThread = CommWithServer::Instance()->m_pClientSocketThread;
							pThread->AddPacketReceived(pPacket);
						
						
						m_nRecvDataLen = sizeof(DWORD);
						m_nBytesRecv = 0;
						m_nRecvStatus = RecvId;
					}
					break;
					
				default:
					ASSERT(false);
					break;
				} 
			}
		}
		else 
		{	// else error occurred
			if (GetLastError() != WSAEWOULDBLOCK) 
			{
				m_nBytesRecv = m_nRecvDataLen;
				TRACE0("Socket Error. Unable to read data.\n");
			} 
			else
			{
				TRACE0("CServerSocket: WARNING: WSAEWOULDBLOCK on a Receive in OnReceive.\n");
			}
		}
	}
	
	CAsyncSocket::OnReceive(nErrorCode);
}

void CClientSocket::OnSend(int nErrorCode) 
{
	// TODO: Add your specialized code here and/or call the base class
	DoAsyncSend();
	
	CAsyncSocket::OnSend(nErrorCode);
}

void CClientSocket::AsyncSend(Packet * pPacket)
{
  if (m_lpbySendBuf) delete m_lpbySendBuf;
  DWORD dwDataSize = pPacket->GetDataSize();
	m_nSendDataLen = sizeof(DWORD)*2+dwDataSize;
  m_lpbySendBuf = new BYTE[m_nSendDataLen];
  memcpy(m_lpbySendBuf, (LPBYTE)&pPacket->m_dwId, sizeof(DWORD));
  memcpy(&m_lpbySendBuf[sizeof(DWORD)], (LPBYTE)&dwDataSize, sizeof(DWORD));
  memcpy(&m_lpbySendBuf[sizeof(DWORD)*2], pPacket->GetpData(), dwDataSize);
  m_nBytesSent = 0;
  DoAsyncSend();
}

void CClientSocket::DoAsyncSend()
{
	while (m_nBytesSent < m_nSendDataLen)  
	{
		int nBytes;

		if ((nBytes = Send((const void *)&m_lpbySendBuf[m_nBytesSent], m_nSendDataLen-m_nBytesSent)) == SOCKET_ERROR)
		{
			if (GetLastError() == WSAEWOULDBLOCK) 
      {
				break;
      }
			else
			{
        TRACE1("Server Socket failed to send: %d.\n", GetLastError());
				m_nBytesSent = 0;
				m_nSendDataLen = 0;
				return;
			}
		}
		else
		{
			m_nBytesSent += nBytes;
		}
	}

	if (m_nBytesSent == m_nSendDataLen)
	{
		m_nBytesSent = m_nSendDataLen = 0;
	}
}
